﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

using ColladaDotNet.OpenTKMapping;

using OpenTK;
using OpenTK.Graphics.OpenGL;

namespace ColladaDotNet.Viewer
{
	public partial class ColladaViewer : Form
	{
		private static double angle = 0.0f;

		private Document doc;

		private readonly GLControl glControl;

		public ColladaViewer()
		{
			InitializeComponent();
			
			glControl = new GLControl();
			glControl.Dock = DockStyle.Fill;
			Controls.Add(glControl);
		}

		protected override void OnResize(EventArgs e)
		{
			base.OnResize(e);
		}

		protected override void OnMouseWheel(MouseEventArgs e)
		{
			base.OnMouseWheel(e);
			var scene = CurrentScene;
			if (scene != null)
			{
				if (scene.ActiveCamera != null)
				{
					var cam = scene.ActiveCamera;
					int delta = -e.Delta;
					Matrix4d offset = Matrix4d.CreateTranslation(
							delta * cam.Matrix.M31, delta * cam.Matrix.M32, delta * cam.Matrix.M33);
					cam.Matrix = cam.Matrix * offset;
				}
			}
			
		}

		
		protected override void OnClosing(CancelEventArgs e)
		{
			Application.Idle -= Application_Idle;

			base.OnClosing(e);
		}

		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);

			doc = new Document();
			//doc.Load(@"D:\GLoom\_CHARACTER\MALE\male_naked_lod2.dae");
			
			//var name = "ColladaDotNet.Viewer.Samples.snake.DAE";
			//var name = "ColladaDotNet.Viewer.Samples.walking_biped_phys.DAE";
			//var name = "ColladaDotNet.Viewer.Samples.multimaterial.DAE";
			//var name = "ColladaDotNet.Viewer.Samples.clockwork.DAE";
			//var name = "ColladaDotNet.Viewer.Samples.tile.DAE";
			//var name = "ColladaDotNet.Viewer.Samples.solidwall.DAE";
			//using (
			//        var stream =
			//                typeof(ColladaViewer).Assembly.GetManifestResourceStream(name))
			//{
			//    doc.Load(stream);
			//}

			glControl.KeyDown += new KeyEventHandler(glControl_KeyDown);
			glControl.KeyUp += glControl_KeyUp;
			glControl.Resize += new EventHandler(glControl_Resize);
			glControl.Paint += new PaintEventHandler(glControl_Paint);

			Text = OpenTK.Graphics.OpenGL.GL.GetString(OpenTK.Graphics.OpenGL.StringName.Vendor) + " " + GL.GetString(StringName.Renderer) + " "
			       + GL.GetString(StringName.Version);

			GL.ClearColor(Color.White);
			GL.Enable(EnableCap.DepthTest);

			Application.Idle += Application_Idle;

			// Ensure that the viewport and projection matrix are set correctly.
			glControl_Resize(glControl, EventArgs.Empty);
		}

		private void DrawCube()
		{
            GL.Begin(BeginMode.Quads);

            GL.Color3(Color.Silver);
            GL.Vertex3(-1.0f, -1.0f, -1.0f);
            GL.Vertex3(-1.0f, 1.0f, -1.0f);
            GL.Vertex3(1.0f, 1.0f, -1.0f);
            GL.Vertex3(1.0f, -1.0f, -1.0f);

            GL.Color3(Color.Honeydew);
            GL.Vertex3(-1.0f, -1.0f, -1.0f);
            GL.Vertex3(1.0f, -1.0f, -1.0f);
            GL.Vertex3(1.0f, -1.0f, 1.0f);
            GL.Vertex3(-1.0f, -1.0f, 1.0f);

            GL.Color3(Color.Moccasin);

            GL.Vertex3(-1.0f, -1.0f, -1.0f);
            GL.Vertex3(-1.0f, -1.0f, 1.0f);
            GL.Vertex3(-1.0f, 1.0f, 1.0f);
            GL.Vertex3(-1.0f, 1.0f, -1.0f);

            GL.Color3(Color.IndianRed);
            GL.Vertex3(-1.0f, -1.0f, 1.0f);
            GL.Vertex3(1.0f, -1.0f, 1.0f);
            GL.Vertex3(1.0f, 1.0f, 1.0f);
            GL.Vertex3(-1.0f, 1.0f, 1.0f);

            GL.Color3(Color.PaleVioletRed);
            GL.Vertex3(-1.0f, 1.0f, -1.0f);
            GL.Vertex3(-1.0f, 1.0f, 1.0f);
            GL.Vertex3(1.0f, 1.0f, 1.0f);
            GL.Vertex3(1.0f, 1.0f, -1.0f);

            GL.Color3(Color.ForestGreen);
            GL.Vertex3(1.0f, -1.0f, -1.0f);
            GL.Vertex3(1.0f, 1.0f, -1.0f);
            GL.Vertex3(1.0f, 1.0f, 1.0f);
            GL.Vertex3(1.0f, -1.0f, 1.0f);

            GL.End();
		}

		private DateTime prevTime = new DateTime(1,1,1);
		VisualScene CurrentScene
		{
			get
			{
				VisualScene scene = null;
				if (doc != null)
				{
					scene = doc.VisualScene;
					if (scene == null && doc.VisualScenes.Count > 0)
						scene = doc.VisualScenes[0];
				}
				return scene;
			}
		}
		private void Render()
		{
			if (prevTime == new DateTime(1, 1, 1))
				prevTime = DateTime.Now;

			GL.Viewport(0, 0, glControl.ClientSize.Width, glControl.ClientSize.Height);


			VisualScene scene = CurrentScene;
			
            //GL.Rotate(angle, 1.0f, 1.0f, 0.0f);
			DateTime now = DateTime.Now;
            angle += now.Subtract(prevTime).TotalSeconds;
			prevTime = now;

	

			GL.ClearColor(Color.Black);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

			//DrawCube();

		    

			if (scene != null)
			{
				GL.Enable(EnableCap.DepthTest);
				GL.Disable(EnableCap.CullFace);
				if (scene.ActiveCamera != null)
				{
					
				}
				
				scene.Render((double)glControl.ClientSize.Width / (double)glControl.ClientSize.Height, angle);
				GL.Disable(EnableCap.DepthTest);
				GL.Disable(EnableCap.CullFace);
				Utils.DrawOXY(1000.0f);
				Debug.WriteLine("scene.ChildNodes.Count = " + scene.ChildNodes.Count);
				foreach (var node1 in scene.ChildNodes.ChildNodes)
				{
					RenderPivot(node1);
				}
			}


			glControl.SwapBuffers();
		}

		private void RenderPivot(Node node1)
		{
			GL.MatrixMode(MatrixMode.Modelview);
			GL.PushMatrix();
			var worldMatrix = node1.WorldMatrix;
			GL.MultMatrix(ref worldMatrix);
			Utils.DrawOXY(2.0f);
			GL.PopMatrix();
			foreach (var node2 in node1.ChildNodes.ChildNodes)
			{
				RenderPivot(node2);
			}
		}


		private void Application_Idle(object sender, EventArgs e)
		{
			while (glControl.IsIdle)
			{
				Render();
			}
		}

		private void glControl_KeyDown(object sender, KeyEventArgs e)
		{
			switch (e.KeyData)
			{
				case Keys.Escape:
					Close();
					break;
			}
		}

		private void glControl_KeyUp(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.F12)
			{
				glControl.GrabScreenshot().Save("screenshot.png");
			}
		}

		private void glControl_Paint(object sender, PaintEventArgs e)
		{
			Render();
		}

		private void glControl_Resize(object sender, EventArgs e)
		{
			var c = sender as OpenTK.GLControl;

			if (c.ClientSize.Height == 0)
			{
				c.ClientSize = new System.Drawing.Size(c.ClientSize.Width, 1);
			}

			


		
		}

		private void openToolStripMenuItem_Click(object sender, EventArgs e)
		{
			var ofd = new OpenFileDialog();
			ofd.DefaultExt = "DAE";
			ofd.ValidateNames = false;
			ofd.InitialDirectory = Directory.GetCurrentDirectory();
			if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
			{
				doc = new Document(ofd.FileName);
			}
		}
	}
}